"""DataWarehouse object wrapper."""

from cki_lib.logger import get_logger

from . import settings

LOGGER = get_logger(__name__)


def filter_data(  # noqa: PLR0912
    data, *, checkout_id: str = "", build_id: str = "", test_id: str = ""
) -> dict:
    # pylint: disable=too-many-branches
    """
    Given checkout-all data, add cross references between objects, dropping any orphans.

    Args:
        data: KCIDB schema dict
        checkout_id: filter all builds, tests and results under this ID, and also occurrences
        build_id: filter all tests and results under this ID, and its checkout, and also occurrences
        test_id: filter all results under this ID, and its build and checkout, and also occurrences

    Returns:
        Dict compliant with KCIDB schema, with the filtered data
    """
    if bool(checkout_id) + bool(build_id) + bool(test_id) > 1:
        raise ValueError("Only one ID should be defined")

    if test_id:
        if _tests := {t["id"]: t for t in data.get("tests", []) if t["id"] == test_id}:
            LOGGER.debug("Found a test with the given ID: %s", test_id)
            build_id = _tests[test_id]["build_id"]  # filter parent
        else:
            LOGGER.warning("There's no test with the given ID: %s", test_id)
            return {k: [] for k in data}
    else:
        _tests = {t["id"]: t for t in data.get("tests", [])}

    if build_id:
        if _builds := {b["id"]: b for b in data.get("builds", []) if b["id"] == build_id}:
            LOGGER.debug("Found a build with the given ID: %s", build_id)
            checkout_id = _builds[build_id]["checkout_id"]  # filter parent
        else:
            LOGGER.warning("There's no build with the given ID: %s", build_id)
            return {k: [] for k in data}
    else:
        _builds = {b["id"]: b for b in data.get("builds", [])}

    if checkout_id:
        if _checkouts := {c["id"]: c for c in data.get("checkouts", []) if c["id"] == checkout_id}:
            LOGGER.debug("Found a checkout with the given ID: %s", checkout_id)
        else:
            LOGGER.warning("There's no checkout with the given ID: %s", checkout_id)
            return {k: [] for k in data}
    else:
        _checkouts = {c["id"]: c for c in data.get("checkouts", [])}

    # filter children
    _builds = {b_id: b for b_id, b in _builds.items() if b["checkout_id"] in _checkouts}
    _tests = {t_id: t for t_id, t in _tests.items() if t["build_id"] in _builds}
    _testresults = {r["id"]: r for r in data.get("testresults", []) if r["test_id"] in _tests}

    return {
        "checkouts": list(_checkouts.values()),
        "builds": list(_builds.values()),
        "tests": list(_tests.values()),
        "testresults": list(_testresults.values()),
        # Just in case we are dealing with data already triaged
        "issueoccurrences": [
            i
            for i in data.get("issueoccurrences", [])
            if i["checkout_id"] in _checkouts
            or i["build_id"] in _builds
            or i["test_id"] in _tests
            or i["testresult_id"] in _testresults
        ],
    }


def get_manager_for_obj_type(obj_type: str):
    """Map obj_type to DW API managers."""
    return {
        'checkout': settings.DW_CLIENT.kcidb.checkouts,
        'build': settings.DW_CLIENT.kcidb.builds,
        'test': settings.DW_CLIENT.kcidb.tests,
        'testresult': settings.DW_CLIENT.kcidb.testresults,
    }[obj_type]


def from_obj_id(obj_type: str, obj_id):
    """Fetch a DW object of a given type, and add a type field to it."""
    obj = get_manager_for_obj_type(obj_type).get(obj_id)
    obj.type = obj_type
    return obj


def from_attrs(obj_type: str, attrs):
    """Initialize a DW object of a given type, and add a type field to it."""
    manager = get_manager_for_obj_type(obj_type)
    obj = manager.instantiate(attrs=attrs)
    obj.type = obj_type
    return obj
